#if Gdmp || Gnuf
#elif Gap
using Glodon.Gap.UI;
#endif
using Glodon.Lookup.Services;
using Glodon.Lookup.Services.Contracts;
using Glodon.Lookup.Utils;
using Glodon.Lookup.ViewModels.Contracts;
using Glodon.Lookup.ViewModels.Pages;
using Glodon.Lookup.ViewModels.Pages.Tracebale;
using Glodon.Lookup.Views.Pages;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Versioning;

using Wpf.Ui.Contracts;
using Wpf.Ui.Services;

namespace Glodon.Lookup
{
    public static class Host
    {
        private static IHost _host = null;
        public static ActionEventHandler ActionEventHandler { get; private set; } = new ActionEventHandler();
        public static async Task StartHost()
        {
            if (_host != null)
            {
                return;
            }
            IHostBuilder builder = Microsoft.Extensions.Hosting.Host
                .CreateDefaultBuilder()
                .ConfigureAppConfiguration(builder =>
                {

                    var assembly = Assembly.GetExecutingAssembly();
                    var assemblyLocation = assembly.Location;
                    var addinVersion = FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion;

                    var userDataLocation = Path.GetDirectoryName(assemblyLocation);

                    var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
                    var writeAccess = AccessUtils.CheckWriteAccess(assemblyLocation) && !assemblyLocation.StartsWith(appDataPath);

                    var targetFrameworkAttributes = assembly.GetCustomAttributes(typeof(TargetFrameworkAttribute), true);
                    var targetFrameworkAttribute = (TargetFrameworkAttribute)targetFrameworkAttributes.First();
                    var targetFramework = targetFrameworkAttribute.FrameworkDisplayName;

                    builder.AddInMemoryCollection(new KeyValuePair<string, string?>[]
                    {
                        new("Assembly", assemblyLocation),
                        new("Framework", targetFramework),
                        new("AddinVersion", addinVersion),
                        new("ConfigFolder", Path.Combine(userDataLocation, "Config")),
                        new("DownloadFolder", Path.Combine(userDataLocation, "Downloads")),
                        new("FolderAccess", writeAccess ? "Write" : "Read")
                    });
                });

            _host = builder.ConfigureServices((_, services) =>
            {
                try
                {
                    services.AddSingleton<ISettingsService, SettingsService>();

                    services.AddScoped<IWindowController, WindowController>();
                    services.AddScoped<INavigationService, NavigationService>();
                    services.AddScoped<ISnackbarService, SnackbarService>();
                    services.AddScoped<IContentDialogService, ContentDialogService>();

                    services.AddScoped<SettingsViewModel>();
                    services.AddScoped<ISnoopService, SnoopViewModel>();
                    services.AddScoped((Func<IServiceProvider, ITabGroupViewModel<SnoopHistoryViewModel>>)((sp) =>
                    {
                        SnoopViewModel snoopViewModel = sp.GetService<ISnoopService>() as SnoopViewModel;
                        return snoopViewModel;
                    }));

                    services.AddScoped<IWindow, GLookupWindow>();
                }
                catch (Exception e)
                {
                    ExceptionUtils.ShowExceptionMessage(e);
                }

            }).Build();
            await _host.StartAsync();

        }

        public static async Task StopHost()
        {
            await _host.StopAsync();
            _host.Dispose();
        }

        public static T GetService<T>() where T : class
        {
            try
            {
                return _host.Services.GetService(typeof(T)) as T;
            }
            catch (Exception e)
            {
                ExceptionUtils.ShowExceptionMessage(e);
                return null;
            }
        }
    }
}
